﻿using System;
using System.Collections.Generic;
using System.Linq;

using ParamsDict = System.Collections.Generic.IDictionary<string, string>;

namespace QuickTuner.RadioProtocol.Modules
{
    public abstract class ProtocolModuleBase
    {
        public delegate bool CanExecuteDelegate(ParamsDict parameters);

        public delegate void ExecuteDelegate(ParamsDict parameters);

        protected struct ActionItem
        {
            public string Name { get; set; }
            public CanExecuteDelegate CanExecute { get; set; }
            public ExecuteDelegate Execute { get; set; }
        }

        private readonly Dictionary<string, ActionItem> _actions;
        private IRadio _target;

        public abstract string Name { get; }

        public IRadio Target { get { return _target; } set { _target = value; } }

        // constructors _________________________________________________________________

        protected ProtocolModuleBase() : this(null) { }

        protected ProtocolModuleBase(IRadio target)
        {
            _target = target;

            _actions = new Dictionary<string, ActionItem>();

            OnInitActions();
        }

        // methods ______________________________________________________________________

        protected abstract void OnInitActions();

        protected void RegisterAction(string action, CanExecuteDelegate canExecuteFunction,
            ExecuteDelegate executeFunction)
        {
            action = action.ToUpper();

            _actions.Add(action, new ActionItem {
                Name = action,
                CanExecute = canExecuteFunction,
                Execute = executeFunction
            });
        }

        public string[] GetAllActions() { return _actions.Keys.ToArray(); }

        public bool CanExecute(string action, IDictionary<string, string> parameters)
        {
            if (string.IsNullOrEmpty(action))
                return false;

            action = action.ToUpper();

            // shortcircuiting
            return
                _target != null &&
                _actions.ContainsKey(action) &&
                _actions[action].CanExecute(parameters);
        }

        public void Execute(string action, IDictionary<string, string> parameters)
        {
            if (_target == null)
                throw new InvalidOperationException("No target radio specified");

            if (!CanExecute(action, parameters))
                throw new ArgumentException("Unknown action or invalid parameters");

            action = action.ToUpper();

            _actions[action].Execute(parameters);
        }
    }
}